#include "rtc.h"

/** converts BCD (Binary Coded Decimal) to decimal
 */
Byte bcd2dec(Byte i) {
    return (i & 0x0F) + 10 * ((i >> 4) & 0x0F);
}

/** converts decimal to BCD (Binary Coded Decimal)
 */
Byte dec2bcd(Byte i) {
    return (i % 10) + (((i / 10) % 10) << 4);
}

/** Wait until data in rtc is valid.
 * Data is valid until +/- 240 usec after this function returns,
 * thus a read/write can be done to the RTC within this time period
 */

//funcoes das interrupcoes

void rtc_int_enable_periodic() {
    write_rtc(RTC_STAT_B, (read_rtc(RTC_STAT_B) & 0x8F) | RTC_PIE);
    read_rtc(RTC_STAT_C);
}

void rtc_int_disable() {
    write_rtc(RTC_STAT_B, read_rtc(RTC_STAT_B) & ~(RTC_PIE | RTC_AIE | RTC_UIE));
}

//----------------

/** Returns rtc data from I/O address add. Doesn't check valid bit
 */
void rtc_valid() {
    int old_pic1 = get_pic1(), old_pic2 = get_pic2();
    set_pic_var(0xFF, 0xFF);

    outportb(RTC_ADDR_REG, RTC_STAT_A); // read STAT_A

    // wait if Update In Progress (UIP)
    while (inportb(RTC_DATA_REG) & RTC_UIP)
        ; // data is invalid

    set_pic_var(old_pic1, old_pic2);
}

Byte read_rtc(Byte add) {
    int old_pic1 = get_pic1(), old_pic2 = get_pic2();
    set_pic_var(0xFF, 0xFF);

    outportb(RTC_ADDR_REG, add);
    Byte val = inportb(RTC_DATA_REG);

    set_pic_var(old_pic1, old_pic2);
    return val;
}

/** Returns rtc data from I/O address add. Check valid bit
 */
Byte read_rtcv(Byte add) {
    rtc_valid();
    return read_rtc(add);
}

/** Write value to I/O address add. Doesn't check valid bit
 */
void write_rtc(Byte add, Byte value) {
    int old_pic1 = get_pic1(), old_pic2 = get_pic2();
    set_pic_var(0xFF, 0xFF);

    outportb(RTC_ADDR_REG, add);
    outportb(RTC_DATA_REG, value);

    set_pic_var(old_pic1, old_pic2);
}

/** Write value to I/O address add. Check valid bit
 */
void write_rtcv(Byte add, Byte value) {
    rtc_valid();
    write_rtc(add, value);
}

/** Read RTC stored time
 *
 * Uses read_rtcv() and bcd2dec()
 */
void rtc_read_time(RTC_TIME * rt) {
    rt->hour = bcd2dec(read_rtcv(HOUR));
    rt->min = bcd2dec(read_rtcv(MIN));
    rt->sec = bcd2dec(read_rtcv(SEC));
}

/** Read RTC stored date
 *
 * Uses read_rtcv() and bcd2dec()
 */
void rtc_read_date(RTC_DATE * rd) {
    rd->year = bcd2dec(read_rtcv(YEAR));
    rd->month = bcd2dec(read_rtcv(MONTH));
    rd->day = bcd2dec(read_rtcv(MONTH_DAY));
}

/** Read RTC stored alarm
 *
 * Uses read_rtcv() and bcd2dec()
 */
void rtc_read_alarm(RTC_TIME *rt) {
    rt->hour = bcd2dec(read_rtcv(HOUR_ALARM));
    rt->min = bcd2dec(read_rtcv(MIN_ALARM));
    rt->sec = bcd2dec(read_rtcv(SEC_ALARM));
}

/** Write alarm to RTC
 *
 * Uses write_rtcv() and dec2bcd()
 */
void rtc_write_alarm(RTC_TIME *rt) {
    write_rtcv(HOUR_ALARM, dec2bcd(rt->hour));
    write_rtcv(MIN_ALARM, dec2bcd(rt->min));
    write_rtcv(SEC_ALARM, dec2bcd(rt->sec));
}

/** @} end of RealTimeController */
